import os
import json
import pandas as pd
from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.views import View
from django.conf import settings
from sklearn.preprocessing import StandardScaler
from utils.network_structure import *

# Create predict views here.
# 将上传的文件名作为全局变量保存
file_name = ''
select_mode = ''

# 上传测试集，接收测试集
class Upload(View):
    """预测功能：上传测试集"""

    def get(self, request):
        return render(request, 'predict/predict-upload.html', context={'message': "上传测试集"})

    def post(self, request):
        global file_name
        try:
            csv_file = request.FILES.get('csv_file')
            file_name = csv_file.name
            if file_name.split('.')[1] != 'csv':
                return render(request, 'predict/predict-upload.html', context={'message': '文件格式错误'})
            file_path = os.path.join(settings.MEDIA_ROOT, 'code\\'+file_name)

            # 学到
            with open(file_path, 'wb+') as f:
                for chunk in csv_file.chunks():
                    f.write(chunk)

            return redirect('predict:select_mode')
        except Exception as e:
            print(e)
            return render(request, 'predict/predict-upload.html', context={'message': '上传出错，请重新上传'})


# 执行预测
def execute_predict(request):

    global file_name
    global num_epochs
    global learning_rate
    global in_channels
    global out_channels
    global kernel_size
    global num_classes
    global select_mode

    # 对最终测试集进行预测
    dataset_test = pd.read_csv(os.path.join(settings.MEDIA_ROOT, 'code\\'+file_name))

    # 判断是否是单条还是批量测试样本
    if len(dataset_test) == 1:
        # print('dataset_test只有一行数据(不包括列名)')
        dataset_test = dataset_test.drop(['sample_id'], axis=1)
    else:
        dataset_test = dataset_test.drop(['sample_id'], axis=1)
    if select_mode == 'your':
        # 判断是否存在本地模型，选择用户上传的模型或者是本地模型
        if not os.path.exists(os.path.join(settings.MEDIA_ROOT, "model\\1dcnn-select2.pth")):
            return render(request, 'train/train-upload.html', context={'message': '尚不存在模型，请先进行训练'})

    dataset_test[np.isnan(dataset_test)] = 0

    # 经过随机森林特征选择后，去除对分类影响小的特征
    columns_to_select = [
        'feature64', 'feature32', 'feature54', 'feature88',
        'feature65', 'feature92', 'feature80', 'feature1',
        'feature78', 'feature60', 'feature20', 'feature77',
        'feature57', 'feature100'
    ]
    # 标准化处理
    scaler = StandardScaler()
    dataset_test = dataset_test.drop(columns=columns_to_select)
    test_dataset = dataset_test.values[:, 0:]
    test_dataset = scaler.fit_transform(test_dataset)
    test_dataset = test_dataset.reshape(test_dataset.shape[0], 93, 1).astype('float32')
    test_dataset = torch.from_numpy(test_dataset).float()
    device = get_default_device()
    # 选择模型
    if select_mode == 'our':
        model_name = os.path.join(settings.STATICFILES_DIRS[0], "model\\1dcnn-best.pth")
        print(model_name)
    else:
        model_name = os.path.join(settings.MEDIA_ROOT, "model\\1dcnn-select2.pth")
        print(model_name)

    model = to_device(OneDCNN(num_classes, in_channels, out_channels, kernel_size), device)
    model.load_state_dict(torch.load(model_name))

    model.eval()
    model.to(device)
    test_pred = model(to_device(test_dataset, device))
    test_pred = test_pred.cpu().detach().numpy()
    np.argmax(test_pred, axis=1)
    value_counts = np.bincount(np.argmax(test_pred, axis=1))
    # print(value_counts)

    # 将预测结果整理为字典形式
    predictions = {}
    sample_ids = dataset_test.values[:, 0].astype(int)
    predicted_labels = np.argmax(test_pred, axis=1)
    for sample_id, label in zip(sample_ids, predicted_labels):
        predictions[str(sample_id)] = int(label)

    # 将字典保存为JSON文件
    output_file = os.path.join(settings.MEDIA_ROOT, 'result\\' + 'predictions.json')
    with open(output_file, "w") as f:
        json.dump(predictions, f)

    # print("预测结果已保存为JSON文件：", output_file)

    # 处理可视化
    # unique横坐标类别数量
    # counts纵坐标每类的数量
    unique, counts = np.unique(np.argmax(test_pred, axis=1), return_counts=True)
    context = {
        'unique': unique.tolist(),
        'counts': counts.tolist(),
    }
    # 渲染到可视化的HTML中
    return render(request, 'predict/predict-visualization.html', context)


# 开放下载分类结果
def download(request):
    # 读取要下载的文件
    filepath = os.path.join(settings.MEDIA_ROOT, 'result\\' + 'predictions.json')
    with open(filepath, 'rb') as f:
        filedata = f.read()

    # 返回响应，弹出文件下载对话框
    response = HttpResponse(filedata, content_type='application/json')
    response['Content-Disposition'] = 'attachment; filename="prediction.json"'

    return response


# 选择模型，才能进行下一步预测
class SelectMode(View):
    def get(self, request):
        # return redirect('predict:execute_predict')
        return render(request, 'predict/predict-select-mode.html')

    def post(self, request):

        global select_mode
        select_mode = request.POST.get('select_mode')
        return redirect('predict:execute_predict')
